package com.syni.mdd.yhd.common.all.utils;

import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @className SpecificationUtils
 * @description TOO
 * @Author cfx
 * @DATE 2019/7/9 14:18
 * @VERSION 1.0
 **/
public class SpecificationUtils implements Specification {
    public static String EQ = "EQ";
    public static String NEQ = "NEQ";
    public static String LIKE = "LIKE";
    public static String NOLIKES = "NOLIKES";
    public static String GT = "GT";
    public static String LT = "LT";
    public static String GTT= "GTT";
    public static String LTT = "LTT";
    public static String GTTE= "GTTE";
    public static String LTTE = "LTTE";
    public static String IN = "IN";
    public static String NIN = "NIN";
    public static String GB  = "GB";
    public static String NN  = "NN";
    public static String N = "N";
    public enum Operator {
        EQ, LIKE, GT, LT, GTE, LTE, NN, N, IN, NEQ
    }
    private Map<String,Object> conditionMap;
    private Map<String,Object> groupMap;

    public SpecificationUtils(Map<String,Object> paramsMap) {
        this.conditionMap = paramsMap;
    }

    public SpecificationUtils(Map<String,Object> paramsMap,Map<String,Object> groupMap) {
        this.conditionMap = paramsMap;
        this.groupMap = groupMap;
    }

    @Override
    public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicates = new ArrayList<>();
        if(conditionMap.size() > 0) {
            for (Map.Entry<String, Object> condition : conditionMap.entrySet()) {
                String searchStr = condition.getKey();
                String[] ruleName = searchStr.split("_");
                if (ruleName.length == 1) {
                    predicates.add(criteriaBuilder.equal(root.get(ruleName[0]), condition.getValue()));
                }
                if (ruleName.length > 1) {
                    String rootName = ruleName[0];
                    String rule = ruleName[1];
                    if (EQ.equals(rule)) {
                        predicates.add(criteriaBuilder.equal(root.get(rootName), condition.getValue()));
                    }else if(NEQ.equals(rule)){
                        predicates.add(criteriaBuilder.notEqual(root.get(rootName), condition.getValue()));
                    } else if (LIKE.equals(rule)) {
                        predicates.add(criteriaBuilder.like(root.get(rootName), "%" + condition.getValue() + "%"));
                    }else if(NOLIKES.equals(rule)){
                        predicates.add(criteriaBuilder.notLike(root.get(rootName), "%" + condition.getValue() + "%"));
                    } else if (GT.equals(rule)) {
                        predicates.add(criteriaBuilder.gt(root.get(rootName), Integer.parseInt(condition.getValue().toString())));
                    } else if (LT.equals(rule)) {
                        predicates.add(criteriaBuilder.lt(root.get(rootName), Integer.parseInt(condition.getValue().toString())));
                    } else if (IN.equals(rule)) {
                        Set set = (Set) condition.getValue();
                        predicates.add(root.get(rootName).in(set));
                    }else if(NN.equals(rule)){
                        predicates.add(criteriaBuilder.isNotNull(root.get(rootName)));
                    }else if(N.equals(rule)){
                        predicates.add(criteriaBuilder.isNull(root.get(rootName)));
                    } else if (NIN.equals(rule)) {
                        Set set = (Set) condition.getValue();
                        predicates.add(criteriaBuilder.not(root.get(rootName).in(set)));
                    }else if (GTT.equals(rule)) {
                        predicates.add(criteriaBuilder.greaterThan(root.get(rootName), (Comparable)condition.getValue()));
                    } else if (LTT.equals(rule)) {
                        predicates.add(criteriaBuilder.lessThan(root.get(rootName), (Comparable)condition.getValue()));
                    }else if (GTTE.equals(rule)) {
                        predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(rootName), (Comparable)condition.getValue()));
                    } else if (LTTE.equals(rule)) {
                        predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(rootName), (Comparable)condition.getValue()));
                    }
                }
            }
        }
        criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()]));
        if(groupMap != null && groupMap.size() > 0) {
            for (Map.Entry<String, Object> condition : groupMap.entrySet()) {
                String searchStr = condition.getKey();
                String[] ruleName = searchStr.split("_");
                if (ruleName.length == 1) {
                    continue;
                }
                if (ruleName.length > 1) {
                    String rootName = ruleName[0];
                    String rule = ruleName[1];
                    if (GB.equals(rule)) {
                        criteriaQuery.groupBy(root.get(rootName));
                    }
                }
            }
        }
        return null;
    }


}
